From 290e87f34d197d2bb1468863c8edab73eeb6bc69 Mon Sep 17 00:00:00 2001 From: "cl349@freefall.cl.cam.ac.uk" Date: Wed, 10 Nov 2004 20:50:47 +0000 Subject: [PATCH] bitkeeper revision 1.1159.1.405 (41927f27DOMh29BHDXqA1jRKSnc6Qg) SMP IPI support. --- .../arch/xen/i386/kernel/smp.c | 179 +++++++----------- .../arch/xen/i386/kernel/smpboot.c | 60 +++--- .../arch/xen/kernel/evtchn.c | 48 +++-- .../asm-xen/asm-i386/mach-xen/irq_vectors.h | 14 +- .../include/asm-xen/asm-i386/system.h | 99 +++++----- xen/common/event_channel.c | 52 +++-- 6 files changed, 230 insertions(+), 222 deletions(-) diff --git a/linux-2.6.9-xen-sparse/arch/xen/i386/kernel/smp.c b/linux-2.6.9-xen-sparse/arch/xen/i386/kernel/smp.c index 0c0260daf2..b2f7f461e7 100644 --- a/linux-2.6.9-xen-sparse/arch/xen/i386/kernel/smp.c +++ b/linux-2.6.9-xen-sparse/arch/xen/i386/kernel/smp.c @@ -25,6 +25,7 @@ #if 0 #include #endif +#include #define xxprint(msg) HYPERVISOR_console_io(CONSOLEIO_write, strlen(msg), msg) @@ -125,35 +126,47 @@ static inline int __prepare_ICR2 (unsigned int mask) return SET_APIC_DEST_FIELD(mask); } -void __send_IPI_shortcut(unsigned int shortcut, int vector) -{ -#if 1 - xxprint("__send_IPI_shortcut\n"); -#else - /* - * Subtle. In the case of the 'never do double writes' workaround - * we have to lock out interrupts to be safe. As we don't care - * of the value read we use an atomic rmw access to avoid costly - * cli/sti. Otherwise we use an even cheaper single atomic write - * to the APIC. - */ - unsigned int cfg; +DECLARE_PER_CPU(int, ipi_to_evtchn[NR_IPIS]); - /* - * Wait for idle. - */ - apic_wait_icr_idle(); - - /* - * No need to touch the target chip field - */ - cfg = __prepare_ICR(shortcut, vector); +static inline void __send_IPI_one(unsigned int cpu, int vector) +{ + unsigned int evtchn; + + evtchn = per_cpu(ipi_to_evtchn, cpu)[vector]; + // printk("send_IPI_mask_bitmask cpu %d vector %d evtchn %d\n", cpu, vector, evtchn); + if (evtchn) { + shared_info_t *s = HYPERVISOR_shared_info; + while (synch_test_bit(evtchn, &s->evtchn_pending[0]) || + synch_test_bit(evtchn, &s->evtchn_mask[0])) + ; + notify_via_evtchn(evtchn); + } else + printk("send_IPI to unbound port %d/%d", + cpu, vector); +} - /* - * Send the IPI. The write to APIC_ICR fires this off. - */ - apic_write_around(APIC_ICR, cfg); -#endif +void __send_IPI_shortcut(unsigned int shortcut, int vector) +{ + int cpu; + + switch (shortcut) { + case APIC_DEST_SELF: + __send_IPI_one(smp_processor_id(), vector); + break; + case APIC_DEST_ALLBUT: + for (cpu = 0; cpu < NR_CPUS; ++cpu) { + if (cpu == smp_processor_id()) + continue; + if (cpu_isset(cpu, cpu_online_map)) { + __send_IPI_one(cpu, vector); + } + } + break; + default: + printk("XXXXXX __send_IPI_shortcut %08x vector %d\n", shortcut, + vector); + break; + } } void fastcall send_IPI_self(int vector) @@ -164,86 +177,26 @@ void fastcall send_IPI_self(int vector) /* * This is only used on smaller machines. */ -void send_IPI_mask_bitmask(cpumask_t cpumask, int vector) +void send_IPI_mask_bitmask(cpumask_t mask, int vector) { -#if 1 - xxprint("send_IPI_mask_bitmask\n"); - dump_stack(); -#else - unsigned long mask = cpus_addr(cpumask)[0]; - unsigned long cfg; unsigned long flags; + unsigned int cpu; local_irq_save(flags); - - /* - * Wait for idle. - */ - apic_wait_icr_idle(); - - /* - * prepare target chip field - */ - cfg = __prepare_ICR2(mask); - apic_write_around(APIC_ICR2, cfg); - - /* - * program the ICR - */ - cfg = __prepare_ICR(0, vector); - - /* - * Send the IPI. The write to APIC_ICR fires this off. - */ - apic_write_around(APIC_ICR, cfg); + + for (cpu = 0; cpu < NR_CPUS; ++cpu) { + if (cpu_isset(cpu, mask)) { + __send_IPI_one(cpu, vector); + } + } local_irq_restore(flags); -#endif } inline void send_IPI_mask_sequence(cpumask_t mask, int vector) { -#if 1 - xxprint("send_IPI_mask_sequence\n"); -#else - unsigned long cfg, flags; - unsigned int query_cpu; - /* - * Hack. The clustered APIC addressing mode doesn't allow us to send - * to an arbitrary mask, so I do a unicasts to each CPU instead. This - * should be modified to do 1 message per cluster ID - mbligh - */ - - local_irq_save(flags); - - for (query_cpu = 0; query_cpu < NR_CPUS; ++query_cpu) { - if (cpu_isset(query_cpu, mask)) { - - /* - * Wait for idle. - */ - apic_wait_icr_idle(); - - /* - * prepare target chip field - */ - cfg = __prepare_ICR2(cpu_to_logical_apicid(query_cpu)); - apic_write_around(APIC_ICR2, cfg); - - /* - * program the ICR - */ - cfg = __prepare_ICR(0, vector); - - /* - * Send the IPI. The write to APIC_ICR fires this off. - */ - apic_write_around(APIC_ICR, cfg); - } - } - local_irq_restore(flags); -#endif + send_IPI_mask_bitmask(mask, vector); } #include /* must come after the send_IPI functions above for inlining */ @@ -325,7 +278,8 @@ static inline void leave_mm (unsigned long cpu) * 2) Leave the mm if we are in the lazy tlb mode. */ -asmlinkage void smp_invalidate_interrupt (void) +irqreturn_t smp_invalidate_interrupt(int irq, void *dev_id, + struct pt_regs *regs) { unsigned long cpu; @@ -351,16 +305,14 @@ asmlinkage void smp_invalidate_interrupt (void) } else leave_mm(cpu); } -#if 1 - xxprint("smp_invalidate_interrupt ack_APIC_irq\n"); -#else - ack_APIC_irq(); -#endif + xxprint("smp_invalidate_interrupt\n"); smp_mb__before_clear_bit(); cpu_clear(cpu, flush_cpumask); smp_mb__after_clear_bit(); out: put_cpu_no_resched(); + + return IRQ_HANDLED; } static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm, @@ -561,10 +513,10 @@ int smp_call_function (void (*func) (void *info), void *info, int nonatomic, /* Wait for response */ while (atomic_read(&data.started) != cpus) barrier(); - if (wait) while (atomic_read(&data.finished) != cpus) barrier(); + spin_unlock(&call_lock); return 0; @@ -609,26 +561,21 @@ void smp_send_stop(void) * all the work is done automatically when * we return from the interrupt. */ -asmlinkage void smp_reschedule_interrupt(void) +irqreturn_t smp_reschedule_interrupt(int irq, void *dev_id, + struct pt_regs *regs) { -#if 1 - xxprint("smp_reschedule_interrupt: ack_APIC_irq\n"); -#else - ack_APIC_irq(); -#endif + + return IRQ_HANDLED; } -asmlinkage void smp_call_function_interrupt(void) +#include +irqreturn_t smp_call_function_interrupt(int irq, void *dev_id, + struct pt_regs *regs) { void (*func) (void *info) = call_data->func; void *info = call_data->info; int wait = call_data->wait; -#if 1 - xxprint("smp_call_function_interrupt: ack_APIC_irq\n"); -#else - ack_APIC_irq(); -#endif /* * Notify initiating CPU that I've grabbed the data and am * about to execute the function @@ -646,5 +593,7 @@ asmlinkage void smp_call_function_interrupt(void) mb(); atomic_inc(&call_data->finished); } + + return IRQ_HANDLED; } diff --git a/linux-2.6.9-xen-sparse/arch/xen/i386/kernel/smpboot.c b/linux-2.6.9-xen-sparse/arch/xen/i386/kernel/smpboot.c index f492b5a5db..846292b788 100644 --- a/linux-2.6.9-xen-sparse/arch/xen/i386/kernel/smpboot.c +++ b/linux-2.6.9-xen-sparse/arch/xen/i386/kernel/smpboot.c @@ -457,10 +457,7 @@ static struct irqaction local_irq_debug = { void local_setup_debug(void) { - int time_irq; - - time_irq = bind_virq_to_irq(VIRQ_DEBUG); - (void)setup_irq(time_irq, &local_irq_debug); + (void)setup_irq(bind_virq_to_irq(VIRQ_DEBUG), &local_irq_debug); } @@ -484,6 +481,7 @@ int __init start_secondary(void *unused) setup_misdirect_virq(); local_setup_timer(); local_setup_debug(); /* XXX */ + smp_intr_init(); local_irq_enable(); /* * low-memory mappings have been cleared, flush them from @@ -492,7 +490,7 @@ int __init start_secondary(void *unused) local_flush_tlb(); cpu_set(smp_processor_id(), cpu_online_map); wmb(); - if (01) { + if (0) { char *msg2 = "delay2\n"; int timeout; for (timeout = 0; timeout < 50000; timeout++) { @@ -1171,6 +1169,8 @@ static void __init smp_boot_cpus(unsigned int max_cpus) return; } + smp_intr_init(); + #if 0 connect_bsp_APIC(); setup_local_APIC(); @@ -1342,27 +1342,37 @@ void __init smp_cpus_done(unsigned int max_cpus) #endif } -void __init smp_intr_init(void) -{ -#if 1 - xxprint("smp_intr_init\n"); -#else - /* - * IRQ0 must be given a fixed assignment and initialized, - * because it's used before the IO-APIC is set up. - */ - set_intr_gate(FIRST_DEVICE_VECTOR, interrupt[0]); +extern irqreturn_t smp_reschedule_interrupt(int, void *, struct pt_regs *); - /* - * The reschedule interrupt is a CPU-to-CPU reschedule-helper - * IPI, driven by wakeup. - */ - set_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt); +static struct irqaction reschedule_irq = { + smp_reschedule_interrupt, SA_INTERRUPT, CPU_MASK_NONE, "reschedule", + NULL, NULL +}; - /* IPI for invalidation */ - set_intr_gate(INVALIDATE_TLB_VECTOR, invalidate_interrupt); +extern irqreturn_t smp_invalidate_interrupt(int, void *, struct pt_regs *); - /* IPI for generic function call */ - set_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt); -#endif +static struct irqaction invalidate_irq = { + smp_invalidate_interrupt, SA_INTERRUPT, CPU_MASK_NONE, "invalidate", + NULL, NULL +}; + +extern irqreturn_t smp_call_function_interrupt(int, void *, struct pt_regs *); + +static struct irqaction call_function_irq = { + smp_call_function_interrupt, SA_INTERRUPT, CPU_MASK_NONE, + "call_function", NULL, NULL +}; + +void __init smp_intr_init(void) +{ + + (void)setup_irq( + bind_ipi_on_cpu_to_irq(smp_processor_id(), RESCHEDULE_VECTOR), + &reschedule_irq); + (void)setup_irq( + bind_ipi_on_cpu_to_irq(smp_processor_id(), INVALIDATE_TLB_VECTOR), + &invalidate_irq); + (void)setup_irq( + bind_ipi_on_cpu_to_irq(smp_processor_id(), CALL_FUNCTION_VECTOR), + &call_function_irq); } diff --git a/linux-2.6.9-xen-sparse/arch/xen/kernel/evtchn.c b/linux-2.6.9-xen-sparse/arch/xen/kernel/evtchn.c index 688816372c..9794af7b2e 100644 --- a/linux-2.6.9-xen-sparse/arch/xen/kernel/evtchn.c +++ b/linux-2.6.9-xen-sparse/arch/xen/kernel/evtchn.c @@ -63,8 +63,7 @@ static int irq_to_evtchn[NR_IRQS]; /* IRQ <-> VIRQ mapping. */ DEFINE_PER_CPU(int, virq_to_irq[NR_VIRQS]); -#define NR_IPIS 8 -/* IRQ <-> IPI mapping. */ +/* evtchn <-> IPI mapping. */ DEFINE_PER_CPU(int, ipi_to_evtchn[NR_IPIS]); /* Reference counts for bindings to IRQs. */ @@ -196,38 +195,56 @@ void unbind_virq_from_irq(int virq) spin_unlock(&irq_mapping_update_lock); } -void bind_ipi_on_cpu(int cpu, int ipi) +int bind_ipi_on_cpu_to_irq(int cpu, int ipi) { evtchn_op_t op; + int evtchn, irq; spin_lock(&irq_mapping_update_lock); - if (per_cpu(ipi_to_evtchn, cpu)[ipi] == 0) { + if ( (evtchn = per_cpu(ipi_to_evtchn, cpu)[ipi]) == 0 ) + { op.cmd = EVTCHNOP_bind_ipi; op.u.bind_ipi.ipi_edom = cpu; if ( HYPERVISOR_event_channel_op(&op) != 0 ) panic("Failed to bind virtual IPI %d on cpu %d\n", ipi, cpu); + evtchn = op.u.bind_ipi.port; - per_cpu(ipi_to_evtchn, cpu)[ipi] = op.u.bind_ipi.port; - } + irq = find_unbound_irq(); + evtchn_to_irq[evtchn] = irq; + irq_to_evtchn[irq] = evtchn; + + per_cpu(ipi_to_evtchn, cpu)[ipi] = evtchn; + } else + irq = evtchn_to_irq[evtchn]; + + irq_bindcount[irq]++; spin_unlock(&irq_mapping_update_lock); + + return irq; } -void unbind_ipi_on_cpu(int cpu, int ipi) +void unbind_ipi_on_cpu_from_irq(int cpu, int ipi) { evtchn_op_t op; int evtchn = per_cpu(ipi_to_evtchn, cpu)[ipi]; + int irq = irq_to_evtchn[evtchn]; spin_lock(&irq_mapping_update_lock); - op.cmd = EVTCHNOP_close; - op.u.close.dom = DOMID_SELF; - op.u.close.port = evtchn; - if ( HYPERVISOR_event_channel_op(&op) != 0 ) - panic("Failed to unbind virtual IPI %d on cpu %d\n", ipi, cpu); + if ( --irq_bindcount[irq] == 0 ) + { + op.cmd = EVTCHNOP_close; + op.u.close.dom = DOMID_SELF; + op.u.close.port = evtchn; + if ( HYPERVISOR_event_channel_op(&op) != 0 ) + panic("Failed to unbind virtual IPI %d on cpu %d\n", ipi, cpu); - per_cpu(ipi_to_evtchn, cpu)[ipi] = 0; + evtchn_to_irq[evtchn] = -1; + irq_to_evtchn[irq] = -1; + per_cpu(ipi_to_evtchn, cpu)[ipi] = 0; + } spin_unlock(&irq_mapping_update_lock); } @@ -538,10 +555,11 @@ void __init init_IRQ(void) spin_lock_init(&irq_mapping_update_lock); - /* No VIRQ -> IRQ mappings. */ - for ( cpu = 0; cpu < NR_CPUS; cpu++ ) + for ( cpu = 0; cpu < NR_CPUS; cpu++ ) { + /* No VIRQ -> IRQ mappings. */ for ( i = 0; i < NR_VIRQS; i++ ) per_cpu(virq_to_irq, cpu)[i] = -1; + } /* No event-channel -> IRQ mappings. */ for ( i = 0; i < NR_EVENT_CHANNELS; i++ ) diff --git a/linux-2.6.9-xen-sparse/include/asm-xen/asm-i386/mach-xen/irq_vectors.h b/linux-2.6.9-xen-sparse/include/asm-xen/asm-i386/mach-xen/irq_vectors.h index b00f02fc94..75647adc8f 100644 --- a/linux-2.6.9-xen-sparse/include/asm-xen/asm-i386/mach-xen/irq_vectors.h +++ b/linux-2.6.9-xen-sparse/include/asm-xen/asm-i386/mach-xen/irq_vectors.h @@ -34,6 +34,7 @@ * Vectors 0x20-0x2f are used for ISA interrupts. */ +#if 0 /* * Special IRQ vectors used by the SMP architecture, 0xf0-0xff * @@ -56,6 +57,7 @@ * sources per level' errata. */ #define LOCAL_TIMER_VECTOR 0xef +#endif /* * First APIC vector available to drivers: (vectors 0x30-0xee) @@ -65,8 +67,6 @@ #define FIRST_DEVICE_VECTOR 0x31 #define FIRST_SYSTEM_VECTOR 0xef -/* #define TIMER_IRQ _EVENT_TIMER */ - /* * 16 8259A IRQ's, 208 potential APIC interrupt sources. * Right now the APIC is mostly only used for SMP. @@ -77,6 +77,12 @@ * the usable vector space is 0x20-0xff (224 vectors) */ +#define NR_IPIS 8 + +#define RESCHEDULE_VECTOR 1 +#define INVALIDATE_TLB_VECTOR 2 +#define CALL_FUNCTION_VECTOR 3 + /* * The maximum number of vectors supported by i386 processors * is limited to 256. For processors other than i386, NR_VECTORS @@ -138,8 +144,8 @@ /* Dynamic binding of event channels and VIRQ sources to Linux IRQ space. */ extern int bind_virq_to_irq(int virq); extern void unbind_virq_from_irq(int virq); -extern void bind_ipi_on_cpu(int cpu, int ipi); -extern void unbind_ipi_on_cpu(int cpu, int ipi); +extern int bind_ipi_on_cpu_to_irq(int cpu, int ipi); +extern void unbind_ipi_on_cpu_from_irq(int cpu, int ipi); extern int bind_evtchn_to_irq(int evtchn); extern void unbind_evtchn_from_irq(int evtchn); diff --git a/linux-2.6.9-xen-sparse/include/asm-xen/asm-i386/system.h b/linux-2.6.9-xen-sparse/include/asm-xen/asm-i386/system.h index bcb1a9e7c2..565685b55a 100644 --- a/linux-2.6.9-xen-sparse/include/asm-xen/asm-i386/system.h +++ b/linux-2.6.9-xen-sparse/include/asm-xen/asm-i386/system.h @@ -443,71 +443,80 @@ struct alt_instr { /* * The use of 'barrier' in the following reflects their use as local-lock * operations. Reentrancy must be prevented (e.g., __cli()) /before/ following - * critical operations are executed. All critical operatiosn must complete + * critical operations are executed. All critical operations must complete * /before/ reentrancy is permitted (e.g., __sti()). Alpha architecture also * includes these barriers, for example. */ -#define __cli() \ -do { \ - HYPERVISOR_shared_info->vcpu_data[0].evtchn_upcall_mask = 1; \ - barrier(); \ +#define __cli() \ +do { \ + vcpu_info_t *_vcpu = \ + &HYPERVISOR_shared_info->vcpu_data[smp_processor_id()]; \ + _vcpu->evtchn_upcall_mask = 1; \ + barrier(); \ } while (0) -#define __sti() \ -do { \ - shared_info_t *_shared = HYPERVISOR_shared_info; \ - barrier(); \ - _shared->vcpu_data[0].evtchn_upcall_mask = 0; \ - barrier(); /* unmask then check (avoid races) */ \ - if ( unlikely(_shared->vcpu_data[0].evtchn_upcall_pending) ) \ - force_evtchn_callback(); \ +#define __sti() \ +do { \ + vcpu_info_t *_vcpu = \ + &HYPERVISOR_shared_info->vcpu_data[smp_processor_id()]; \ + barrier(); \ + _vcpu->evtchn_upcall_mask = 0; \ + barrier(); /* unmask then check (avoid races) */ \ + if ( unlikely(_vcpu->evtchn_upcall_pending) ) \ + force_evtchn_callback(); \ } while (0) -#define __save_flags(x) \ -do { \ - (x) = HYPERVISOR_shared_info->vcpu_data[0].evtchn_upcall_mask; \ +#define __save_flags(x) \ +do { \ + vcpu_info_t *_vcpu = \ + &HYPERVISOR_shared_info->vcpu_data[smp_processor_id()]; \ + (x) = _vcpu->evtchn_upcall_mask; \ } while (0) -#define __restore_flags(x) \ -do { \ - shared_info_t *_shared = HYPERVISOR_shared_info; \ - barrier(); \ - if ( (_shared->vcpu_data[0].evtchn_upcall_mask = (x)) == 0 ) { \ - barrier(); /* unmask then check (avoid races) */ \ - if ( unlikely(_shared->vcpu_data[0].evtchn_upcall_pending) ) \ - force_evtchn_callback(); \ - } \ +#define __restore_flags(x) \ +do { \ + vcpu_info_t *_vcpu = \ + &HYPERVISOR_shared_info->vcpu_data[smp_processor_id()]; \ + barrier(); \ + if ( (_vcpu->evtchn_upcall_mask = (x)) == 0 ) { \ + barrier(); /* unmask then check (avoid races) */ \ + if ( unlikely(_vcpu->evtchn_upcall_pending) ) \ + force_evtchn_callback(); \ + } \ } while (0) -#define safe_halt() ((void)0) +#define safe_halt() ((void)0) -#define __save_and_cli(x) \ -do { \ - (x) = HYPERVISOR_shared_info->vcpu_data[0].evtchn_upcall_mask; \ - HYPERVISOR_shared_info->vcpu_data[0].evtchn_upcall_mask = 1; \ - barrier(); \ +#define __save_and_cli(x) \ +do { \ + vcpu_info_t *_vcpu = \ + &HYPERVISOR_shared_info->vcpu_data[smp_processor_id()]; \ + (x) = _vcpu->evtchn_upcall_mask; \ + _vcpu->evtchn_upcall_mask = 1; \ + barrier(); \ } while (0) -#define __save_and_sti(x) \ -do { \ - shared_info_t *_shared = HYPERVISOR_shared_info; \ - barrier(); \ - (x) = _shared->vcpu_data[0].evtchn_upcall_mask; \ - _shared->vcpu_data[0].evtchn_upcall_mask = 0; \ - barrier(); /* unmask then check (avoid races) */ \ - if ( unlikely(_shared->vcpu_data[0].evtchn_upcall_pending) ) \ - force_evtchn_callback(); \ +#define __save_and_sti(x) \ +do { \ + vcpu_info_t *_vcpu = \ + &HYPERVISOR_shared_info->vcpu_data[smp_processor_id()]; \ + barrier(); \ + (x) = _vcpu->evtchn_upcall_mask; \ + _vcpu->evtchn_upcall_mask = 0; \ + barrier(); /* unmask then check (avoid races) */ \ + if ( unlikely(_vcpu->evtchn_upcall_pending) ) \ + force_evtchn_callback(); \ } while (0) #define local_irq_save(x) __save_and_cli(x) -#define local_irq_restore(x) __restore_flags(x) -#define local_save_flags(x) __save_flags(x) -#define local_irq_disable() __cli() -#define local_irq_enable() __sti() +#define local_irq_restore(x) __restore_flags(x) +#define local_save_flags(x) __save_flags(x) +#define local_irq_disable() __cli() +#define local_irq_enable() __sti() #define irqs_disabled() \ - HYPERVISOR_shared_info->vcpu_data[0].evtchn_upcall_mask + HYPERVISOR_shared_info->vcpu_data[smp_processor_id()].evtchn_upcall_mask /* * disable hlt during certain critical i/o operations diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c index 6ada9f3e28..5d4ac4d4ef 100644 --- a/xen/common/event_channel.c +++ b/xen/common/event_channel.c @@ -28,26 +28,28 @@ #define INIT_EVENT_CHANNELS 16 #define MAX_EVENT_CHANNELS 1024 +#define EVENT_CHANNELS_SPREAD 32 -static int get_free_port(struct domain *d) +static int get_free_port(struct exec_domain *ed) { + struct domain *d = ed->domain; int max, port; event_channel_t *chn; max = d->max_event_channel; chn = d->event_channel; - for ( port = 0; port < max; port++ ) + for ( port = ed->eid * EVENT_CHANNELS_SPREAD; port < max; port++ ) if ( chn[port].state == ECS_FREE ) break; - if ( port == max ) + if ( port >= max ) { if ( max == MAX_EVENT_CHANNELS ) return -ENOSPC; - max *= 2; + max = port + EVENT_CHANNELS_SPREAD; chn = xmalloc(max * sizeof(event_channel_t)); if ( unlikely(chn == NULL) ) @@ -57,7 +59,8 @@ static int get_free_port(struct domain *d) if ( d->event_channel != NULL ) { - memcpy(chn, d->event_channel, (max/2) * sizeof(event_channel_t)); + memcpy(chn, d->event_channel, d->max_event_channel * + sizeof(event_channel_t)); xfree(d->event_channel); } @@ -76,7 +79,7 @@ static long evtchn_alloc_unbound(evtchn_alloc_unbound_t *alloc) spin_lock(&d->event_channel_lock); - if ( (port = get_free_port(d)) >= 0 ) + if ( (port = get_free_port(current)) >= 0 ) { d->event_channel[port].state = ECS_UNBOUND; d->event_channel[port].u.unbound.remote_domid = alloc->dom; @@ -139,7 +142,7 @@ static long evtchn_bind_interdomain(evtchn_bind_interdomain_t *bind) /* Obtain, or ensure that we already have, a valid . */ if ( port1 == 0 ) { - if ( (port1 = get_free_port(d1)) < 0 ) + if ( (port1 = get_free_port(ed1)) < 0 ) ERROR_EXIT(port1); } else if ( port1 >= d1->max_event_channel ) @@ -151,7 +154,7 @@ static long evtchn_bind_interdomain(evtchn_bind_interdomain_t *bind) /* Make port1 non-free while we allocate port2 (in case dom1==dom2). */ u16 tmp = d1->event_channel[port1].state; d1->event_channel[port1].state = ECS_INTERDOMAIN; - port2 = get_free_port(d2); + port2 = get_free_port(ed2); d1->event_channel[port1].state = tmp; if ( port2 < 0 ) ERROR_EXIT(port2); @@ -255,7 +258,7 @@ static long evtchn_bind_virq(evtchn_bind_virq_t *bind) */ if ( ((port = ed->virq_to_evtchn[virq]) != 0) || (virq == VIRQ_MISDIRECT) || - ((port = get_free_port(d)) < 0) ) + ((port = get_free_port(ed)) < 0) ) goto out; d->event_channel[port].state = ECS_VIRQ; @@ -283,7 +286,7 @@ static long evtchn_bind_ipi(evtchn_bind_ipi_t *bind) spin_lock(&d->event_channel_lock); - if ( (port = get_free_port(d)) >= 0 ) + if ( (port = get_free_port(ed)) >= 0 ) { d->event_channel[port].state = ECS_IPI; d->event_channel[port].u.ipi_edom = ipi_edom; @@ -312,7 +315,7 @@ static long evtchn_bind_pirq(evtchn_bind_pirq_t *bind) spin_lock(&d->event_channel_lock); if ( ((rc = port = d->pirq_to_evtchn[pirq]) != 0) || - ((rc = port = get_free_port(d)) < 0) ) + ((rc = port = get_free_port(current)) < 0) ) goto out; d->pirq_to_evtchn[pirq] = port; @@ -476,26 +479,39 @@ static long evtchn_send(int lport) { struct domain *ld = current->domain; struct exec_domain *rd; - int rport; + int rport, ret = 0; spin_lock(&ld->event_channel_lock); if ( unlikely(lport < 0) || - unlikely(lport >= ld->max_event_channel) || - unlikely(ld->event_channel[lport].state != ECS_INTERDOMAIN) ) + unlikely(lport >= ld->max_event_channel)) { spin_unlock(&ld->event_channel_lock); return -EINVAL; } - rd = ld->event_channel[lport].u.interdomain.remote_dom; - rport = ld->event_channel[lport].u.interdomain.remote_port; + switch ( ld->event_channel[lport].state ) + { + case ECS_INTERDOMAIN: + rd = ld->event_channel[lport].u.interdomain.remote_dom; + rport = ld->event_channel[lport].u.interdomain.remote_port; - evtchn_set_pending(rd, rport); + evtchn_set_pending(rd, rport); + break; + case ECS_IPI: + rd = ld->exec_domain[ld->event_channel[lport].u.ipi_edom]; + if ( rd ) + evtchn_set_pending(rd, lport); + else + ret = -EINVAL; + break; + default: + ret = -EINVAL; + } spin_unlock(&ld->event_channel_lock); - return 0; + return ret; } -- 2.30.2